JVM JTA

分布式事务

分布式事务是指涉及到多个数据库操作的事务,对于单个数据库的操作,JDBC就能够保证事务的一致性,实际上能够满足数据库事务的ACID特性。那么涉及多数据源之间的操作呢?分布式事务如何保证ACID特性呢?

如果要实现分布式系统的原子性,则须保证所有节点的数据写操作,要不全部都执行(生效),要么全部都不执行(生效)。但是,一个节点在执行本地事务的时候无法知道其它机器的本地事务的执行结果,所以它就不知道本次事务到底应该commit还是 roolback。常规的解决办法是引入一个“协调者”的组件来统一调度所有分布式节点的执行。

XA规范

XA是由X/Open组织提出的分布式事务的规范。XA规范主要定义了(全局)事务管理器(Transaction Manager)(局部)资源管理器(Resource Manager)之间的接口。XA接口是双向的系统接口,在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁。XA引入的事务管理器充当上文所述全局事务中的“协调者”角色。事务管理器控制着全局事务,管理事务生命周期,并协调资源。资源管理器负责控制和管理实际资源(如数据库或JMS队列)。目前,Oracle、Informix、DB2、Sybase和PostgreSQL等各主流数据库都提供了对XA的支持。

XA规范中,事务管理器主要通过以下的接口对资源管理器进行管理

  • xa_open,xa_close:建立和关闭与资源管理器的连接。
  • xa_start,xa_end:开始和结束一个本地事务。
  • xa_prepare,xa_commit,xa_rollback:预提交、提交和回滚一个本地事务。
  • xa_recover:回滚一个已进行预提交的事务。

两阶段提交能保证分布式事务的一致性。

JTA

以上只是数据库的理论知识,还没涉及到实践。而在Java平台上,JTA(Java Transaction API)也定义了对XA事务的支持,实际上,JTA是基于XA架构上建模的。在JTA 中,事务管理器抽象为javax.transaction.TransactionManager接口,并通过底层事务服务(即Java Transaction Service)实现。像很多其他的Java规范一样,JTA仅仅定义了接口,具体的实现则是由供应商(如J2EE厂商)负责提供,目前JTA的实现主要有以下几种:

  • J2EE容器所提供的JTA实现(如JBoss)。

  • 独立的JTA实现:如JOTM(Java Open Transaction Manager),Atomikos。这些实现可以应用在那些不使用J2EE应用服务器的环境里用以提供分布事事务保证。

Hibernate和JTA的关系

Hibernate可以看做JDBC的轻量级的封装,它本身不具有事务管理功能,它要依赖JDBCJTA来实现事务的管理。JDBC只能在单个数据库中事务管理,JTA使用XA协议来管理分布式事务,但是,XA事务的消耗很大,如果不需要分布式事务的建议不要使用。

spring data jpa + jta配置

多数据源,无分布式事务的配置

多数据源,分布式事务的配置

主要区别:

  1. 在配置dataSource时,前者是:bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">使用了c3p0连接池; 而后者是:<bean id="thirdDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"atomikos这个dataSource

  2. entityManagerFactory应该是一样的。

  3. transactionManager后者使用了JtaTransactionManager,里面额外了配置了atomikosTransactionManager等;

    1
    2
    3
    4
    5
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="atomikosTransactionManager" />
    <property name="userTransaction" ref="atomikosUserTransaction" />
    <property name="allowCustomIsolationLevels" value="true" />
    </bean>

而前者使用了JpaTransactionManager

1
2
3
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>